package gepetto.reactor;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.LinkedList;

public class IOHandler extends SelectHandler {
	private static final int BUFFER_SIZE = 4096;
	
	private ByteBuffer inBuffer;
	private ByteBuffer outBuffer;
	
	private LinkedList<IOReadListener> listeners;
	
	public IOHandler(SocketChannel channel) throws IOException {
		super(SelectionKey.OP_READ);
		this.channel = channel;
		this.channel.configureBlocking(false);
		this.inBuffer = ByteBuffer.allocate(BUFFER_SIZE);
		this.outBuffer = ByteBuffer.allocate(BUFFER_SIZE);
		this.listeners = new LinkedList<IOReadListener> ();
	}
	
	@Override
	public boolean handleEvent() {
		SocketChannel channel = (SocketChannel) this.channel;
		int readyOps = channel.keyFor(reactor.getSelector ()).readyOps();
		
		if ((readyOps & SelectionKey.OP_READ) != 0) {
			try {
				int nread = channel.read (inBuffer);
				if (nread >= 0) {
					notifyRead();
				}
				else {
					reactor.unregister(this);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if ((readyOps & SelectionKey.OP_WRITE) != 0) {
			try {
				channel.write (outBuffer);
				if (outBuffer.position() == 0) {
					SelectionKey key = channel.keyFor(reactor.getSelector());
					key.interestOps(SelectionKey.OP_READ);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	public void write (byte [] buffer) {
		outBuffer.put(buffer);
		SelectionKey key = channel.keyFor(reactor.getSelector());
		key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
	}

	private void notifyRead () {
		inBuffer.flip();
		byte [] array = new byte [inBuffer.limit()];
		inBuffer.get(array);
		System.out.print (new String (array));
		for (Iterator<IOReadListener> it = listeners.iterator(); it.hasNext(); ) {
			it.next().handleRead(this, array);
		}
		inBuffer.clear ();
	}
}
